/**
 * skiplist.h
 * 跳表类型和接口声明
 * 
 * 竹影半墙
 * 2023.08
 */
#ifndef SKIPLIST_H
#define SKIPLIST_H

/**
 * 跳表实例任命
 * level  层级数
 * exts   结点扩展长度
 * compar 跳表有序化比较回调
 * step   层级上升概率的分母
 * set    结点数据设置回调
 * clear  结点数据清楚回调
 * around 数据量
 * 
 * @exts  除结点层级指针外用于
 * 承载数据的内存长度，如需64位
 * 存储数据时 @exts = sizeof(uint64_t);
 * 
 * @compar, @set, @clear 回调的第一个参数
 * 为跳表内结点数据内存地址，当 @compar 返
 * 回大于等于 0 时数值时，跳表停止寻找;
 * 
 * @step 为跳表层级概率的分母，如层级上升概率
 * 为 0.25 时，@step=4;
 * 
 * @around 为对任命跳表结点数量的估计值，
 * 当开启了跳表内缓存后，内部会根据该值和
 * 层级数 @level 将各层级的结点内存进行预分配
 */
struct skl_app {
    int level;
    int exts;
    int (*compar)(const void *s, const void *u);
    int step;
    int (*set)(const void *s, const void *u);
    void *(*clear)(void *s);
    unsigned around;
};

/**
 * 内存预分配描述
 * @skl_level 跳表头预分配层数
 * @n_skl 跳表头预分配数
 * @n_cache 跳表结点预分配管理的预分配数
 * 
 * 只有当各参数大于 0 时才会为各项预分配内存
*/
struct skl_cache {
    int skl_level;
    unsigned n_skl;
    unsigned n_cache;
};

#if 0
#endif
/**
 * 初始化 @ca 指定的内存预分配管理
 * 
 * 当调用 skl_init 时
 * @app->around != 0 且
 * @app->level == @ca->skl_level 时,
 * 会在 @ca->n_skl 个已分配 skl 中分配 skl,
 * 会在 @ca->n_cache 个已分配的内存预分配管
 * 理器中为各层级结点分配预分配内存管理器；
 * 
 * 否则，没有内存预分配流程。
 */
void skl_init_ca(struct skl_cache *ca);
void skl_close_ca(void);

struct skl * skl_init(struct skl_app *app);
void skl_close(struct skl *skl);

void * skl_add (struct skl *skl, const void *u);
void * skl_get (struct skl *skl, const void *u);
void * skl_del (struct skl *skl, const void *u);
void * skl_seek(struct skl *skl, const void *u);
void * skl_seek_first(struct skl *skl);
void * skl_next(struct skl *skl);
#endif